/*
AbacusSim.h: An educational assembly simulator, header file.
    Copyright (C) 2010  Daniel Gutson, FuDePAN

    This file is part of the learn-asm project.

    learn-asm is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    learn-asm is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with learn-asm.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef ABACUS_SIM_H
#define ABACUS_SIM_H

#include <iostream>
#include <stdint.h>

typedef int32_t Value;
static const size_t MAX_MEM = 32u;

class Register;

struct Immediate
{
    explicit Immediate(Value value)
        : value(value) {}

    const Value value;
};

class MemoryAddress
{
    const size_t index;
    void _check() throw(const char*);
protected:
    MemoryAddress(size_t idx);
public:

    MemoryAddress(const MemoryAddress& other);
    void setValue(Value v) const;
    Value getValue() const;

    friend std::ostream& operator << (std::ostream& o, const MemoryAddress& m)
    {
        o << "Address at " << m.index << " contains " << m.getValue();
        return o;
    }
};

class Memory
{
public:
    MemoryAddress operator [] (const Immediate& imm) const;
    MemoryAddress operator [] (const Register& r) const;

};


// basic primitives:
void MovImm(Register& r, const Immediate& imm);
void MovRR(Register& to, const Register& from);
void Load(Register& r, const MemoryAddress& m);
void Store(const MemoryAddress& m, const Register& r);
void Compare(const Register& r1, const Register& r2);
void Compare(const Register& r1, const Immediate& i);
#define JGE(label)	if(CR) goto label
#define JMP(label)  goto label

// arithmetic:
void Add(Register& r, const Register& rOperand);
void Add(Register& r, const Immediate& iOperand);
void Mul(Register& r, const Register& rOperand);
void Mul(Register& r, const Immediate& iOperand);

// debug:
void PrintReg(const Register& r);
void PrintMem(const MemoryAddress& m);
void PrintAllRegs();
void PrintAllMem();
void PrintAll();

#define BEGIN_MEMORY    \
{   Value init[MAX_MEM] = {
#define END_MEMORY      \
}; void _InitMem(const Value init[MAX_MEM]); _InitMem(init);  }


// declarations:

extern Register R1, R2, R3, R4;
extern Memory memory;
extern bool CR;

// Program declarations:

#define BEGIN_PROGRAM	int main() { try {

#define END_PROGRAM		} catch(const char* err) { std::cerr << err << std::endl; } }
#endif

